package com.xsjiong.iamath;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class Main {
	private static JFrame F;
	private static JPanel P;
	private static Graphics2D G;

	public static void main(String[] args) {
		Interval x = new Interval(-0.01953125,0.0);
		System.out.println(x.CreateClone().sin().divide(x));
		F = new JFrame("Graph");
		F.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		F.setResizable(false);
		F.setVisible(true);
		P = new JPanel();
		P.setPreferredSize(new Dimension(500, 500));
		P.addMouseListener(new MouseListener() {
			@Override
			public void mouseClicked(MouseEvent e) {
				final int L = 10;
				PostGraph(-L, -L, L * 2);
			}

			@Override
			public void mousePressed(MouseEvent e) {
			}

			@Override
			public void mouseReleased(MouseEvent e) {
			}

			@Override
			public void mouseEntered(MouseEvent e) {
			}

			@Override
			public void mouseExited(MouseEvent e) {
			}
		});
		F.setContentPane(P);
		F.pack();
	}

	private static void PrintDouble(double a) {
		long l = Double.doubleToRawLongBits(a);
		boolean[] d = new boolean[64];
		for (int i = 63; i >= 0; i--) {
			d[i] = (l & 1) == 1;
			l >>= 1;
		}
		for (int i = 0; i < 64; i++)
			System.out.print(d[i] ? '1' : '0');
		System.out.println(Double.toHexString(a));
	}

	private static boolean Working = false;

	private static void PostGraph(final double stx, final double sty, final double size) {
		if (Working) return;
		G = (Graphics2D) P.getGraphics();
		Working = true;
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					long st = System.nanoTime();
					PaintPixels(stx, sty, size);
					st = System.nanoTime() - st;
					F.setTitle("Graph - 绘图耗时" + TimeUnit.NANOSECONDS.toMillis(st) + "毫秒");
				} catch (Throwable t) {
					t.printStackTrace();
				}
				Working = false;
			}
		}).start();
	}

	private static int gcd(int a, int b) {
		return b == 0 ? a : gcd(b, a % b);
	}

	private static Interval _X = new Interval(), _Y = new Interval();

	private static Random random = new Random();
	public static boolean F(double xs, double ys, double size) {
		_X.set(xs, xs + size);
		_Y.set(ys, ys + size);
		Interval x = _X, y = _Y;
//		return x.multiply(x).contains(y);
		/*return Interval.E.CreateClone().pow(_X.CreateClone().sin().plus(_Y.CreateClone().cos())).minus(Interval.E.CreateClone().pow(_X.plus(_Y)).sin())
				.innerContains(0);*/
//		return x.CreateClone().multiply(x).plus(y.CreateClone().multiply(y)).sin().minus(x.multiply(y).cos()).innerContains(0);
//		return x.multiply(y).sin().contains(0);
//		return new Interval(1).divide(x).minus(y).innerContains(0);
//		return x.CreateClone().sin().divide(x).contains(y);
//		return Interval.ONE.CreateClone().divide(x).contains(y);
//		return Interval.ONE.CreateClone().divide(x.sin()).contains(y);
//		return x.CreateClone().multiply(x).minus(y.CreateClone().multiply(y)).sin().abs().contains(x.CreateClone().plus(y).sin().plus(x.CreateClone().multiply(y).cos()));
//		return x.CreateClone().multiply(x).plus(x.CreateClone().multiply(2).multiply(y)).sin().abs().contains(x.CreateClone().minus(y.multiply(2)).sin());
//		return x.CreateClone().sin().plus(y.CreateClone().cos()).sin().contains(y.multiply(x).sin().plus(x.cos()).cos());
		return x.plus(Interval.ONE.CreateClone().divide(x)).contains(y);
	}

	private static class SquareRegion {
		double x, y, size;
		int rx, ry, rsize;

		public SquareRegion(double x, double y, int rx, int ry, double size, int rsize) {
			this.x = x;
			this.y = y;
			this.rx = rx;
			this.ry = ry;
			this.size = size;
			this.rsize = rsize;
		}

		@Override
		public String toString() {
			return "[[" + x + ',' + (x + size) + "], [" + y + ',' + (y + size) + "]]";
		}
	}

	private static Interval tmpa = new Interval(), tmpb = new Interval();

	private static Queue<SquareRegion> Q = new LinkedBlockingQueue<>();

	private static SquareRegion fillRect(SquareRegion r) {
//		System.out.println(r.rx + " " + r.ry + " " + r.rsize);
		G.fillRect(r.rx, r.ry, r.rsize, r.rsize);
		return r;
	}

	private static final Color BACKGROUND = Color.decode("#2196F3"), UNCERTAINED = Color.decode("#FF0000"), GRAPH = Color.decode("#FFFFFF");

	public static void PaintPixels(double left, double bottom, double size) {
		int ssize = P.getWidth();
		double scale = (double) ssize / size;
		double top = bottom + size;
		G.setColor(Color.BLACK);
		int tmp = (int) (top * scale);
		G.drawLine(0, tmp, ssize, tmp);
		tmp = (int) (-left * scale);
		G.drawLine(tmp, 0, tmp, ssize);
		Q.add(new SquareRegion(left, bottom, 0, 0, size, ssize));
		SquareRegion tp;
		double lastSize = size;
		double pixelSize = (double) size / P.getWidth();
		while (!Q.isEmpty()) {
			tp = Q.remove();
			if (tp.size != lastSize) {
				lastSize = tp.size;
				System.out.println("下一阶段: " + tp.size);
				try {
//					Thread.sleep(1500);
				} catch (Throwable e) {
					e.printStackTrace();
				}
			}
			boolean has = F(tp.x, tp.y, tp.size);
			if (!has) {
				G.setColor(BACKGROUND);
				fillRect(tp);
//				System.out.println(tp + " 中没有解");
				continue;
			}
			if (tp.size >= pixelSize) {
				double s2 = tp.size / 2;
				double stx = tp.rx;
				double sty = tp.ry;
				double rsize = (double) tp.rsize / 2 + 0.5;
				G.setColor(UNCERTAINED);
				/*Q.add(fillRect(new SquareRegion(tp.x, tp.y, (int) stx, (int) (sty + rsize), s2, (int) rsize)));
				Q.add(fillRect(new SquareRegion(tp.x + s2, tp.y, (int) (stx + rsize), (int) (sty + rsize), s2, (int) rsize)));
				Q.add(fillRect(new SquareRegion(tp.x, tp.y + s2, (int) stx, (int) sty, s2, (int) rsize)));
				Q.add(fillRect(new SquareRegion(tp.x + s2, tp.y + s2, (int) (stx + rsize), (int) sty, s2, (int) rsize)));*/
				fillRect(tp);
				Q.add(new SquareRegion(tp.x, tp.y, (int) stx, (int) (sty + rsize), s2, (int) rsize));
				Q.add(new SquareRegion(tp.x + s2, tp.y, (int) (stx + rsize), (int) (sty + rsize), s2, (int) rsize));
				Q.add(new SquareRegion(tp.x, tp.y + s2, (int) stx, (int) sty, s2, (int) rsize));
				Q.add(new SquareRegion(tp.x + s2, tp.y + s2, (int) (stx + rsize), (int) sty, s2, (int) rsize));
			} else {
				if (tp.x < 0 && tp.x + tp.size >= 0) System.out.println(tp + " 小于精度，绘制");
				G.setColor(GRAPH);
				fillRect(tp);
			}
		}
		System.out.println("Over");
	}
}